#include "stdafx.h"
#define MYLIB_API_EXPORT

#include "ComponentConnectivityGraph.h"
#include "KernelConverter.h"

//initialize the static member
std::auto_ptr<CompGraph> CompGraph::_instance(0);

void CompGraph::build_graph(ModelOBJ* obj,float size, int bFlag, float tol)
{
	if (el.size() != 0)
	{
		return;
	}
	//step1 closing or expansion
	std::vector<Nef_polyhedron_3*> Nefpolylist;
	SOLID_const_itr itr = obj->begin();
	int stanumber = 0;
	while(itr != obj->end())
	{
		SolidOBJ* solid = *itr++;

		//kernel conversion
		EK_Poly_3 ek_poly;
		if (!CKernelConverter::GetSingleton()->IK_to_EK(solid->Solid_mesh, &ek_poly))
		{
			return;
		}

		//
		Nef_polyhedron_3* poly = new Nef_polyhedron_3(ek_poly);

		//shrink model
		if (tol >0)
		{
			poly = CMorphologicalProc::GetSingleton()->ReversMinKowskisum(poly,tol);				
		}
		//closing
		if (bFlag == 1)
		{//wood
			poly = CMorphologicalProc::GetSingleton()->MinKowskisum(poly,size);
			poly = CMorphologicalProc::GetSingleton()->ReversMinKowskisum(poly,size);
		}
		else if(bFlag == 0)
		{//stone
			poly = CMorphologicalProc::GetSingleton()->MinKowskisum(poly,size);
		}
		Nefpolylist.push_back(poly);
		std::cout<<stanumber++<<std::endl;
	}
	//clear the original model for release memory
	if (obj)
	{
		SOLID_itr solid_itr = obj->begin();
		while(solid_itr != obj->end())
		{
			SolidOBJ* curS = *solid_itr;
			if (curS)
			{
				delete curS;
				curS = NULL;
			}
			++solid_itr;
		}
		obj->clear();
		delete obj;
		obj = NULL;
	}
	//step2 collision detection
	std::cout<<"---------------------------"<<std::endl<<"Collision Detection.."<<std::endl
		<<"---------------------------"<<std::endl;
	std::vector<Nef_polyhedron_3*>::iterator Nefpoly_itr = Nefpolylist.begin();
	while(Nefpoly_itr != Nefpolylist.end())
	{
		Nef_polyhedron_3* poly = *Nefpoly_itr++;
		bool bIsSole = true;
		//
		std::vector<Nef_polyhedron_3*>::iterator sub_Nefpoly_itr = Nefpoly_itr;
		while(sub_Nefpoly_itr != Nefpolylist.end())
		{
			Nef_polyhedron_3* comp_poly = *sub_Nefpoly_itr++;
			//collision detection
			if (detect_collision(poly,comp_poly))
			{
				//whether there is an edge containing the same nodes
				bool bIsExist = false;
				EdgeList::iterator el_itr = el.begin();
				while(el_itr != el.end()&&el.size()>1)
				{
					Edge* e = *el_itr++;
					if ((e->first == poly || e->first == comp_poly)&&
						(e->second == comp_poly || e->second == poly))
					{
						bIsExist = true;
						break;
					}
				}
				if (!bIsExist)
				{
					//create edge
					Edge* e = new Edge;
					e->first = poly;
					e->second = comp_poly;
					el.push_back(e);
				}
				//detect single solid
				bIsSole = false;
			}
		}
		//add single solid as an edge
		if (bIsSole)
		{
			//whether there is an edge containing this node
			bool bIsExist = false;
			EdgeList::iterator el_itr = el.begin();
			while(el_itr != el.end()&&el.size()>1)
			{
				Edge* e = *el_itr++;
				if (e->first == poly || e->second == poly)
				{
					bIsExist = true;
					break;
				}
			}
			if (!bIsExist)
			{
				//create edge
				Edge* e = new Edge;
				e->first = poly;
				e->second = poly;
				el.push_back(e);
			}
		}
	}
}

bool CompGraph::combine_polys()
{
	bool bIsComblined = false;
	if (el.size() == 0)
	{
		return false;
	}
	//combine all the polyhedrons
	EdgeList::iterator el_itr = el.begin();
	while(el_itr != el.end()&&el.size() > 0)
	{
		Edge* e = *el_itr;
		if (handle_edge(e))
		{
			//updated
			el_itr = el.begin();
			bIsComblined = true;
		}
		else
		{
			el_itr++;
		}
	}
	//clean the redundancy of CompGraph(subgraph is represented by an edge)
	// 		NodeList nodes;
	// 		el_itr = el.begin();
	// 		nodes.push_back((*el_itr++)->first);
	// 		while(el_itr != el.end())
	// 		{
	// 			Nef_polyhedron_3* n = (*el_itr)->first;
	// 			if (std::find(nodes.begin(),nodes.end(),n) != nodes.end())
	// 			{
	// 				del_edge((*el_itr++));
	// 			}
	// 			else
	// 			{
	// 				nodes.push_back((*el_itr++)->first);
	// 			}
	// 		}

	return bIsComblined;
}

void CompGraph::add_edge(Edge* e)
{
	if (e != NULL)
	{
		el.push_back(e);
	}
}

bool CompGraph::del_edge(Edge* e)
{
	EdgeList::iterator pos = std::find(el.begin(),el.end(),e);
	if (pos != el.end())
	{
		el.erase(pos);
		return true;
	}
	else
		return false;
}

bool CompGraph::handle_edge(Edge* e)
{
	Nef_polyhedron_3* comb = NULL;
	Nef_polyhedron_3* poly1, *poly2;
	poly1 = e->first;
	poly2 = e->second;
	if(poly2 != poly1)
	{
		comb = new Nef_polyhedron_3(*poly2 + *poly1);
	}
	else
	{
		return false;
	}

	//update edgelist
	EdgeList::iterator el_itr = el.begin();
	bool bIsAffected = false; //whether there are other affect edges (only one node is affected)
	EdgeList TobeDel_Edges;//record the redundant edges
	NodeList TobeDel_Polys; //record the old polys
	while(el_itr != el.end())
	{
		Edge* ed = *el_itr++;
		int uStaNum = 0;
		if (ed->first == poly2||ed->first == poly1)//update
		{
			//move to trash can
			if (std::find(TobeDel_Polys.begin(), TobeDel_Polys.end(),ed->first) == TobeDel_Polys.end())
			{
				TobeDel_Polys.push_back(ed->first);
			}
			//assign new poly
			ed->first = comb;
			uStaNum++;
		}
		if (ed->second == poly2||ed->second == poly1)//update
		{
			//move to trash can
			if (std::find(TobeDel_Polys.begin(), TobeDel_Polys.end(),ed->second) == TobeDel_Polys.end())
			{
				TobeDel_Polys.push_back(ed->second);
			}
			//assign new poly
			ed->second = comb;
			uStaNum++;
		}
		if (uStaNum == 2)
		{//record this edge
			TobeDel_Edges.push_back(ed);
		}
		else if (uStaNum > 0)
		{//set the tag
			bIsAffected = true;
		}
	}
	//delete edges
	if (bIsAffected)
	{//all deleted
		EdgeList::iterator el_itr = TobeDel_Edges.begin();
		while(el_itr != TobeDel_Edges.end()&&TobeDel_Edges.size()>0)
		{
			if (!del_edge(*el_itr++))
			{
				std::cout<<"fatal error in handle_edge"<<std::endl;
			}
		}
	}
	else if (TobeDel_Edges.size()>1)
	{//all deleted but one is left
		EdgeList::iterator el_itr = TobeDel_Edges.begin();
		while(el_itr != TobeDel_Edges.end()-1)
		{
			if (!del_edge(*el_itr++))
			{
				std::cout<<"fatal error in handle_edge"<<std::endl;
			}
		}
	}
	//delete polys
	NodeList::iterator poly_itr = TobeDel_Polys.begin();
	while (poly_itr != TobeDel_Polys.end() && TobeDel_Polys.size() > 0)
	{
		delete *poly_itr;
		*poly_itr++ = NULL;
	}
	return true;
}

bool CompGraph::detect_collision(Nef_polyhedron_3* poly1, Nef_polyhedron_3* poly2)
{
	Nef_polyhedron_3* test_poly1 = poly1;
	Nef_polyhedron_3* test_poly2 = poly2;
	//intersection
	if (((*test_poly1)*(*test_poly2)).is_empty())
	{
		std::cout<<"false"<<std::endl;
		return false;
	}
	else
	{
		std::cout<<"true"<<std::endl;
		return true;
	}
}